package edu.towson.cosc.cosc455.jkingsbury.compiler;

import java.util.Scanner;
import java.util.Stack;

import edu.towson.cosc.cosc455.interfaces.SyntaxAnalyzer;

/**
 * @author jkings3
 *
 */
public class MySyntaxAnalyzer implements SyntaxAnalyzer {

	public Stack good = new Stack();//Get r
	public int list = 1;//For more than one list
	boolean does = false;
	
	@Override
	public void lolcode() {
		//If there is something after DOC_END
		if(!MyCompiler.Lexer.isEnd()){
			//Try for better error
			System.err.println("SYNTAX ERROR! There should be no more words after " + LexicalTokens.DOC_END + " when some were detected.");
			System.exit(0);
		}
		//If no #HAI opening tag
		if(!MyCompiler.token.equalsIgnoreCase(LexicalTokens.DOC_START)){
			System.err.println("SYNTAX ERROR: " + MyCompiler.token + " when " + LexicalTokens.DOC_START + " was expected.");
			System.exit(0);
		}
		else{
			//If opening tag - push it
			good.push(MyCompiler.token);
			MyCompiler.Lexer.getNextToken();
			//Process it
			//Check for comment
			if (MyCompiler.token.equalsIgnoreCase(LexicalTokens.COMM_BEGIN)){
				does = true;
				good.push(MyCompiler.token);//Push tag
				comment();
				MyCompiler.Lexer.getNextToken();
			}
			//Check for var define
			if (MyCompiler.token.equalsIgnoreCase(LexicalTokens.BEGIN_VAR)){
				does = true;
				good.push(MyCompiler.token);//Push tag
				define();
				MyCompiler.Lexer.getNextToken();
			}
			//Check for head
			if (MyCompiler.token.equalsIgnoreCase(LexicalTokens.BEGIN_HEAD)){
				does = true;
				good.push(MyCompiler.token);//Push tag
				head();
				MyCompiler.Lexer.getNextToken();
			}
			//Starting with title -- illegal
			if (MyCompiler.token.equalsIgnoreCase(LexicalTokens.TITLE_BEGIN)){
				System.err.println("SYNTAX ERROR: " + MyCompiler.token + " must be in a head tag!");
				System.exit(0);
			}
			//If body then good, if never anything in body then bad
			body();
			if(!does && !MyCompiler.token.equalsIgnoreCase(LexicalTokens.DOC_END)){
				System.err.println("SYNTAX ERROR. Illegal being state of: " + MyCompiler.token);
				System.exit(0);
			}
		}
		
		//If not closing tag
		MyCompiler.Lexer.getNextToken();
		if(!MyCompiler.token.equalsIgnoreCase(LexicalTokens.DOC_END)){
			System.err.println("SYNTAX ERROR: " + MyCompiler.token + " when " + LexicalTokens.DOC_END + " was expected.");
			System.exit(0);
		}
		//If closing tag
		else{
			//System.out.println("Good code");
			good.push(MyCompiler.token);
		}
	}

	public void body() {
		while(!MyCompiler.token.equalsIgnoreCase(LexicalTokens.DOC_END)){
			if(MyCompiler.token.equalsIgnoreCase(LexicalTokens.COMM_BEGIN)){
				does = true;
				comment();
			}
			if(MyCompiler.token.equalsIgnoreCase(LexicalTokens.BEGIN_PARA)){
				does = true;
				paragraph();
			}
			if(MyCompiler.token.equalsIgnoreCase(LexicalTokens.BEGIN_ITALIC)){
				does = true;
				italics();
			}
			if(MyCompiler.token.equalsIgnoreCase(LexicalTokens.BEGIN_LIST)){
				does = true;
				list();
			}
			if(MyCompiler.token.equalsIgnoreCase(LexicalTokens.BEGIN_BOLD)){
				does = true;
				bold();
			}
			if(MyCompiler.token.equalsIgnoreCase(LexicalTokens.BEGIN_ITALIC)){
				does = true;
				italics();
			}
			innerText();
			//Absorb text and push
			if(!does){
				System.err.println("SYNTAX ERROR. Illegal being state of: " + MyCompiler.token);
				System.exit(0);
			}
			else
				MyCompiler.Lexer.getNextToken();
		}
	}

	private void innerText() {
		while(!MyCompiler.token.equalsIgnoreCase(LexicalTokens.END_TAG_2) && !MyCompiler.token.equalsIgnoreCase(LexicalTokens.DOC_END)){
			text();
			if(MyCompiler.token.equalsIgnoreCase(LexicalTokens.VISIBLE)){
				does = true;
				use();
			}
			if(MyCompiler.token.equalsIgnoreCase(LexicalTokens.BREAK)){
				does = true;
				newline();
			}
			if(MyCompiler.token.equalsIgnoreCase(LexicalTokens.BEGIN_AUDIO)){
				does = true;
				audio();
			}
			if(MyCompiler.token.equalsIgnoreCase(LexicalTokens.BEGIN_VIDEO)){
				does = true;
				video();
			}
			if(does)
				MyCompiler.Lexer.getNextToken();//Update
			else{
				System.err.println("SYNTAX ERROR. Illegal opening token: " + MyCompiler.token);
				System.exit(0);
			}
		}
	}
	
	@Override
	public void comment() {
		//If here we have the first tag to comment
		//Get inside of comment
		text();
		MyCompiler.Lexer.getNextToken();
		if(MyCompiler.token.equalsIgnoreCase(LexicalTokens.COMM_END)){
			good.push(MyCompiler.token);
		}
		else{
			System.err.println("SYNTAX ERROR:" + MyCompiler.token + " when " + LexicalTokens.COMM_END + " was expected.");
			System.exit(0);
		}
	}

	@Override
	public void head() {
		title();
		//Process closing tag
		MyCompiler.Lexer.getNextToken();
		if(MyCompiler.token.equalsIgnoreCase(LexicalTokens.END_TAG)){
			good.push(MyCompiler.token);
		}
		else{
			System.err.println("SYNTAX ERROR:" + MyCompiler.token + " when " + LexicalTokens.END_TAG + " was expected.");
			System.exit(0);
		}
	}

	@Override
	public void title() {
		MyCompiler.Lexer.getNextToken();
		if(!MyCompiler.token.equalsIgnoreCase(LexicalTokens.TITLE_BEGIN)){
			System.err.println("SYNTAX ERROR:" + MyCompiler.token + " when " + LexicalTokens.TITLE_BEGIN + " was expected.");
			System.exit(0);
		}
		text();
		//Process closing tag
		MyCompiler.Lexer.getNextToken();
		if(MyCompiler.token.equalsIgnoreCase(LexicalTokens.END_TAG_2)){
			good.push(MyCompiler.token);
		}
		else{
			System.err.println("SYNTAX ERROR:" + MyCompiler.token + " when " + LexicalTokens.END_TAG_2 + " was expected.");
			System.exit(0);
		}
	}

	@Override
	//Most likely done
	public void paragraph() {
		MyCompiler.Lexer.getNextToken();
		define();
		innerPara();
		if(MyCompiler.token.equalsIgnoreCase(LexicalTokens.END_TAG)){
			good.push(MyCompiler.token);
		}
		else{
			System.err.println("SYNTAX ERROR:" + MyCompiler.token + " when " + LexicalTokens.END_TAG + " was expected.");
			System.exit(0);
		}
	}

	public void innerPara(){
		boolean passed = true;
		while(!MyCompiler.token.equalsIgnoreCase(LexicalTokens.END_TAG) && passed==true && !MyCompiler.token.equalsIgnoreCase(LexicalTokens.DOC_END)){
			if(MyCompiler.token.equalsIgnoreCase(LexicalTokens.BEGIN_BOLD)){
				bold();
				passed = true;
			}
			if(MyCompiler.token.equalsIgnoreCase(LexicalTokens.BEGIN_ITALIC)){
				italics();
				passed = true;
			}
			if(MyCompiler.token.equalsIgnoreCase(LexicalTokens.BEGIN_LIST)){
				list();
				passed = true;
			}
			if(MyCompiler.token.equalsIgnoreCase(LexicalTokens.BREAK)){
				newline();
				passed = true;
			}
			innerText();//Seemingly causing errors
			if (passed = true){
				MyCompiler.Lexer.getNextToken();//Update
			}
			else{
				passed = false;
			}
		}
	}

	@Override
	public void bold() {
		//If bold beginning token
		if(MyCompiler.token.equalsIgnoreCase(LexicalTokens.BEGIN_BOLD)){
			good.push(MyCompiler.token);
			define();//Check variable define
			innerText();//Check inner text
			if(MyCompiler.token.equalsIgnoreCase(LexicalTokens.END_TAG_2))
				good.push(MyCompiler.token);
			else{//If bad end tag
				System.err.println("SYNTAX ERROR:" + MyCompiler.token + " when " + LexicalTokens.END_TAG_2 + " was expected.");
				System.exit(0);
			}
		}
	}


	private void newline() {
		if(MyCompiler.token.equalsIgnoreCase(LexicalTokens.BREAK)){
			good.push(MyCompiler.token);
		}
		else{
			System.err.println("SYNTAX ERROR:" + MyCompiler.token + " when " + LexicalTokens.BREAK + " was expected.");
			System.exit(0);
		}
	}

	@Override
	public void italics() {
		if(MyCompiler.token.equalsIgnoreCase(LexicalTokens.BEGIN_ITALIC)){
			good.push(MyCompiler.token);
			define();
			innerText();
			if(MyCompiler.token.equalsIgnoreCase(LexicalTokens.END_TAG_2))
				good.push(MyCompiler.token);
			else{//If bad end tag
				System.err.println("SYNTAX ERROR:" + MyCompiler.token + " when " + LexicalTokens.END_TAG_2 + " was expected.");
				System.exit(0);
			}
		}
	}

	@Override
	public void list() {
		if(MyCompiler.token.equalsIgnoreCase(LexicalTokens.BEGIN_LIST)){
			MyCompiler.Lexer.getNextToken();
			//Have to have an item
			if(!MyCompiler.token.equalsIgnoreCase(LexicalTokens.BEGIN_ITEM)){
				System.err.println("SYNTAX ERROR:" + MyCompiler.token + " when " + LexicalTokens.BEGIN_ITEM + " was expected.");
				System.exit(0);
			}
			item();//Not optional
			innerList();//Check for list insides
			MyCompiler.Lexer.getNextToken();
			//Check for more items
			while(MyCompiler.token.equalsIgnoreCase(LexicalTokens.BEGIN_ITEM) || MyCompiler.token.equalsIgnoreCase(LexicalTokens.END_TAG_2)){
				item();
				MyCompiler.Lexer.getNextToken();//Update
			}
			if(MyCompiler.token.equalsIgnoreCase(LexicalTokens.END_TAG)){
				good.push(MyCompiler.token);	
			}
			else{
				System.err.println(" SYNTAX ERROR: " + MyCompiler.token + " when " + LexicalTokens.END_TAG + " was expected.");
				System.exit(0);
			}
		}
	}
	
	@Override
	public void item() {
		if(MyCompiler.token.equalsIgnoreCase(LexicalTokens.BEGIN_ITEM)){
			good.push(MyCompiler.token);
			while(!MyCompiler.token.equalsIgnoreCase(LexicalTokens.END_TAG_2)){
				innerList();
			}
			if(MyCompiler.token.equalsIgnoreCase(LexicalTokens.END_TAG_2)){
				good.push(MyCompiler.token);
			}
			else{
				System.err.println("SYNTAX ERROR: " + MyCompiler.token + " when " + LexicalTokens.END_TAG_2 + " was expected.");
				System.exit(0);
			}
		}
	}

	private void innerList() {
		while(!MyCompiler.token.equalsIgnoreCase(LexicalTokens.END_TAG_2) && !MyCompiler.token.equalsIgnoreCase(LexicalTokens.END_TAG)){
			if(MyCompiler.token.equalsIgnoreCase(LexicalTokens.BEGIN_BOLD)){
				bold();
			}
			if(MyCompiler.token.equalsIgnoreCase(LexicalTokens.BEGIN_ITALIC)){
				italics();
			}
			if(MyCompiler.token.equalsIgnoreCase(LexicalTokens.BEGIN_LIST)){
				list++;
				list();
			}
			innerText();
			//If nested list
			if(list > 1)
				MyCompiler.Lexer.getNextToken();//Update
		}
	}

	@Override
	public void audio() {
		if(MyCompiler.token.equalsIgnoreCase(LexicalTokens.BEGIN_AUDIO)){
			good.push(MyCompiler.token);//Push begin tag
			text();
			MyCompiler.Lexer.getNextToken();//Get end tag
			if(MyCompiler.token.equalsIgnoreCase(LexicalTokens.END_TAG_2))
				good.push(MyCompiler.token);//If good end tag
			else{//If bad end tag
				System.err.println("SYNTAX ERROR: " + MyCompiler.token + " when " + LexicalTokens.END_TAG_2 + " was expected.");
				System.exit(0);
			}
		}
	}


	@Override
	public void video() {
		if(MyCompiler.token.equalsIgnoreCase(LexicalTokens.BEGIN_VIDEO)){
			good.push(MyCompiler.token);//Push begin tag
			text();
			MyCompiler.Lexer.getNextToken();//Get end tag
			if(MyCompiler.token.equalsIgnoreCase(LexicalTokens.END_TAG_2))
				good.push(MyCompiler.token);//If good end tag
			else{//If bad end tag
				System.err.println("SYNTAX ERROR: " + MyCompiler.token + " when " + LexicalTokens.END_TAG_2 + " was expected.");
				System.exit(0);
			}
		}
	}


	@Override
	public void define() {
		if(MyCompiler.token.equalsIgnoreCase(LexicalTokens.BEGIN_VAR)){
			text();
			MyCompiler.Lexer.getNextToken();//ITZ
			if(MyCompiler.token.equalsIgnoreCase(LexicalTokens.VARNAME)){
				text();
				MyCompiler.Lexer.getNextToken();//MKAY
				if(MyCompiler.token.equalsIgnoreCase(LexicalTokens.END_TAG_2)){
					good.push(MyCompiler.token);
				}
				else{
					System.err.println("SYNTAX ERROR: " + MyCompiler.token + " when " + LexicalTokens.END_TAG_2 + " was expected.");
					System.exit(0);
				}
			}
			else{
				System.err.println("SYNTAX ERROR: " + MyCompiler.token + " when " + LexicalTokens.VARNAME + " was expected.");
				System.exit(0);
			}
		}
	}


	@Override
	public void use() {
		if(MyCompiler.token.equalsIgnoreCase(LexicalTokens.VISIBLE)){
			MyCompiler.Lexer.getNextToken();//Get end tag
			if(MyCompiler.token.equalsIgnoreCase(LexicalTokens.END_TAG_2))
				good.push(MyCompiler.token);//If good end tag
			else{//If bad end tag
				System.err.println("SYNTAX ERROR: " + MyCompiler.token + " when " + LexicalTokens.END_TAG_2 + " was expected.");
				System.exit(0);
			}
		}
	}

	private void text() {
		//Watch for potential error here
		if(!does){
			MyCompiler.Lexer.getNextToken();
			good.push(MyCompiler.token);
		}
		char c = MyCompiler.Lexer.peek();
		if(c != '#'){
			does = true;
			MyCompiler.Lexer.getNextToken();
			good.push(MyCompiler.token);
		}
	}	
}
